package cn.lblbc.downloadlib;

import android.util.Log;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import cn.lblbc.downloadlib.ChunkedFileDownloader.PauseChecker;

/**
 * 下载调度器 - 核心调度逻辑：任务队列、并发控制、状态流转
 */
public class DownloadScheduler {
    private static final String TAG = "DownloadScheduler";
    private static volatile DownloadScheduler sInstance;
    private ExecutorService mExecutorService;
    private final int mConcurrentTaskNum;
    private final ConcurrentHashMap<Long, DownloadRunnable> mRunningTasks = new ConcurrentHashMap<>();
    private final FileDownloader mFileDownloader;
    private final ChunkedFileDownloader mChunkedFileDownloader;

    private DownloadScheduler(DownloadConfig config) {
        mConcurrentTaskNum = config.getConcurrentTaskNum();
        mFileDownloader = new FileDownloader();
        mChunkedFileDownloader = new ChunkedFileDownloader();
        initThreadPool();
    }

    public static DownloadScheduler getInstance(DownloadConfig config) {
        if (sInstance == null) {
            synchronized (DownloadScheduler.class) {
                if (sInstance == null) {
                    sInstance = new DownloadScheduler(config);
                }
            }
        }
        return sInstance;
    }

    private void initThreadPool() {
        // 创建线程池，用于执行下载任务
        mExecutorService = new ThreadPoolExecutor(
                mConcurrentTaskNum,  // 核心线程数
                mConcurrentTaskNum,  // 最大线程数
                30, TimeUnit.SECONDS,  // 空闲线程存活时间
                new LinkedBlockingQueue<Runnable>(),  // 任务队列
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
        );
    }

    /**
     * 提交下载任务到线程池执行
     * @param task 下载任务
     */
    public void submitTask(DownloadTask task) {
        Log.d(TAG, "submitTask: Submitting task ID: " + task.getTaskId());
        DownloadRunnable runnable = new DownloadRunnable(task, mFileDownloader, mChunkedFileDownloader);
        mRunningTasks.put(task.getTaskId(), runnable);
        mExecutorService.execute(runnable);
    }

    /**
     * 暂停下载任务
     * @param taskId 任务ID
     */
    public void pauseTask(long taskId) {
        Log.d(TAG, "pauseTask: Pausing task ID: " + taskId);
        DownloadRunnable runnable = mRunningTasks.get(taskId);
        if (runnable != null) {
            Log.d(TAG, "pauseTask: Found running task, pausing it");
            runnable.pause();
        } else {
            Log.d(TAG, "pauseTask: Task not found or not running, updating status in database");
            // 如果任务不在运行列表中，可能是因为任务尚未开始或已完成
            // 直接更新数据库中的状态为暂停（使用PENDING表示）
            try {
                DownloadManager downloadManager = DownloadManager.getInstance();
                downloadManager.updateTaskStatus(taskId, DownloadConstants.STATUS_PENDING);
                // 同时更新任务中所有文件的状态为暂停
                List<DownloadFileDetail> files = downloadManager.getTaskFileDetails(taskId);
                if (files != null) {
                    for (DownloadFileDetail file : files) {
                        downloadManager.updateFileStatus(file.getFileId(), DownloadConstants.STATUS_PENDING);
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, "pauseTask: Error updating task status", e);
            }
        }
    }

    /**
     * 恢复下载任务
     * @param taskId 任务ID
     */
    public void resumeTask(long taskId) {
        Log.d(TAG, "resumeTask: Resuming task ID: " + taskId);
        DownloadRunnable runnable = mRunningTasks.get(taskId);
        if (runnable != null) {
            Log.d(TAG, "resumeTask: Found paused task, resuming it");
            runnable.resume();
        } else {
            Log.d(TAG, "resumeTask: Task not found or not paused, trying to restart it");
            // 如果任务不在运行列表中，则尝试重新启动任务
            restartTask(taskId);
        }
    }

    /**
     * 重新启动任务
     * @param taskId 任务ID
     */
    private void restartTask(long taskId) {
        Log.d(TAG, "restartTask: Restarting task ID: " + taskId);
        DownloadManager downloadManager = DownloadManager.getInstance();
        // 先更新任务状态为等待中，然后再启动下载
        try {
            downloadManager.updateTaskStatus(taskId, DownloadConstants.STATUS_PENDING);
            // 同时更新任务中所有文件的状态为等待中
            List<DownloadFileDetail> files = downloadManager.getTaskFileDetails(taskId);
            if (files != null) {
                for (DownloadFileDetail file : files) {
                    downloadManager.updateFileStatus(file.getFileId(), DownloadConstants.STATUS_PENDING);
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "restartTask: Error updating file status", e);
        }
        downloadManager.startDownload(taskId);
    }

    /**
     * 取消下载任务
     * @param taskId 任务ID
     */
    public void cancelTask(long taskId) {
        Log.d(TAG, "cancelTask: Canceling task ID: " + taskId);
        DownloadRunnable runnable = mRunningTasks.get(taskId);
        if (runnable != null) {
            Log.d(TAG, "cancelTask: Found running task, canceling it");
            runnable.cancel();
            mRunningTasks.remove(taskId);
        } else {
            Log.d(TAG, "cancelTask: Task not found or not running, updating status in database");
            // 如果任务不在运行列表中，直接更新数据库中的状态为取消
            try {
                DownloadManager downloadManager = DownloadManager.getInstance();
                downloadManager.updateTaskStatus(taskId, DownloadConstants.STATUS_CANCELLED);
                // 同时更新任务中所有文件的状态为取消
                List<DownloadFileDetail> files = downloadManager.getTaskFileDetails(taskId);
                if (files != null) {
                    for (DownloadFileDetail file : files) {
                        downloadManager.updateFileStatus(file.getFileId(), DownloadConstants.STATUS_CANCELLED);
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, "cancelTask: Error updating file status", e);
            }
        }
    }
    
    /**
     * 任务完成后的清理工作
     * @param taskId 任务ID
     */
    public void onTaskCompleted(long taskId) {
        Log.d(TAG, "onTaskCompleted: Task completed, removing from running tasks: " + taskId);
        mRunningTasks.remove(taskId);
    }
    
    /**
     * 下载任务Runnable
     */
    private static class DownloadRunnable implements Runnable, FileDownloader.PauseChecker, ChunkedFileDownloader.PauseChecker {
        private final DownloadTask mTask;
        private final FileDownloader mFileDownloader;
        private final ChunkedFileDownloader mChunkedFileDownloader;
        private volatile boolean mPaused = false;
        private volatile boolean mCancelled = false;
        private final Object mPauseLock = new Object();
        
        public DownloadRunnable(DownloadTask task, FileDownloader fileDownloader, ChunkedFileDownloader chunkedFileDownloader) {
            mTask = task;
            mFileDownloader = fileDownloader;
            mChunkedFileDownloader = chunkedFileDownloader;
        }
        
        @Override
        public void run() {
            Log.d(TAG, "DownloadRunnable: Starting download for task ID: " + mTask.getTaskId());
            
            try {
                // 检查是否已取消
                if (mCancelled) {
                    Log.d(TAG, "DownloadRunnable: Task was cancelled before start, task ID: " + mTask.getTaskId());
                    return;
                }
                
                // 检查任务是否有文件列表
                if (mTask.getFiles() == null) {
                    Log.w(TAG, "DownloadRunnable: Task has no files to download, task ID: " + mTask.getTaskId());
                    return;
                }
                
                // 重置任务的已下载大小为0
                try {
                    DownloadManager downloadManager = DownloadManager.getInstance();
                    downloadManager.updateTaskProgress(mTask.getTaskId(), -mTask.getDownloadedSize()); // 减去当前值，相当于重置为0
                } catch (Exception e) {
                    Log.e(TAG, "DownloadRunnable: Error resetting task progress", e);
                }
                
                // 重置所有文件的已下载大小为0
                for (DownloadFileInfo file : mTask.getFiles()) {
                    try {
                        DownloadManager downloadManager = DownloadManager.getInstance();
                        downloadManager.updateFileProgress(file.getFileId(), 0);
                        file.setDownloadedSize(0);
                    } catch (Exception e) {
                        Log.e(TAG, "DownloadRunnable: Error resetting file progress", e);
                    }
                }
                
                // 使用 CountDownLatch 等待所有文件下载完成
                java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(mTask.getFiles().size());
                
                // 下载任务中的所有文件
                for (DownloadFileInfo file : mTask.getFiles()) {
                    // 检查暂停状态
                    synchronized (mPauseLock) {
                        while (mPaused && !mCancelled) {
                            Log.d(TAG, "DownloadRunnable: Task paused, waiting for resume, task ID: " + mTask.getTaskId());
                            try {
                                mPauseLock.wait();
                            } catch (InterruptedException e) {
                                Log.d(TAG, "DownloadRunnable: Interrupted while paused, task ID: " + mTask.getTaskId());
                                Thread.currentThread().interrupt();
                                return;
                            }
                        }
                    }
                    
                    // 检查是否已取消
                    if (mCancelled) {
                        Log.d(TAG, "DownloadRunnable: Task was cancelled, task ID: " + mTask.getTaskId());
                        // 更新任务状态为取消
                        updateTaskStatus(mTask.getTaskId(), DownloadConstants.STATUS_CANCELLED);
                        // 更新所有相关文件状态为取消
                        updateFilesStatus(mTask.getFiles(), DownloadConstants.STATUS_CANCELLED);
                        // 计数器减到0，让任务结束
                        for (int i = 0; i < latch.getCount(); i++) {
                            latch.countDown();
                        }
                        return;
                    }
                    
                    Log.d(TAG, "DownloadRunnable: Downloading file: " + file.getFileName() + 
                        " from URL: " + file.getFileUrl());
                    
                    // 确定文件保存路径
                    String saveDir = file.getSaveDir();
                    if (saveDir == null || saveDir.isEmpty()) {
                        // 使用默认保存目录
                        DownloadManager downloadManager = DownloadManager.getInstance();
                        saveDir = downloadManager.getConfig().getDefaultSaveDir();
                    }
                    
                    // 确保目录存在
                    java.io.File dir = new java.io.File(saveDir);
                    if (!dir.exists()) {
                        dir.mkdirs();
                    }
                    
                    // 设置文件本地路径
                    String localPath = saveDir + "/" + file.getFileName();
                    file.setLocalPath(localPath);
                    
                    // 检查是否启用分片下载
                    DownloadManager downloadManager = DownloadManager.getInstance();
                    DownloadConfig config = downloadManager.getConfig();
                    boolean useChunkedDownload = config.isEnableChunkDownload() && 
                        file.getFileSize() > 10 * 1024 * 1024; // 大于10MB才使用分片
                    
                    if (useChunkedDownload) {
                        // 使用分片下载
                        Log.d(TAG, "DownloadRunnable: Using chunked download for file: " + file.getFileName());
                        List<DownloadChunk> chunks = ChunkUtils.calculateChunks(
                            file.getFileId(), file.getFileSize(), config);
                        downloadFileWithChunks(file, chunks, latch);
                    } else {
                        // 使用普通下载
                        Log.d(TAG, "DownloadRunnable: Using normal download for file: " + file.getFileName());
                        downloadFile(file, latch);
                    }
                }
                
                // 等待所有文件下载完成
                try {
                    latch.await();
                    Log.d(TAG, "DownloadRunnable: Finished download for task ID: " + mTask.getTaskId());
                    // 更新任务状态为完成
                    updateTaskStatus(mTask.getTaskId(), DownloadConstants.STATUS_COMPLETED);
                    // 更新所有相关文件状态为完成
                    updateFilesStatus(mTask.getFiles(), DownloadConstants.STATUS_COMPLETED);
                } catch (InterruptedException e) {
                    Log.d(TAG, "DownloadRunnable: Interrupted while waiting for downloads to complete, task ID: " + mTask.getTaskId());
                    Thread.currentThread().interrupt();
                }
            } finally {
                // 通知调度器任务已完成
                DownloadScheduler scheduler = DownloadScheduler.sInstance;
                if (scheduler != null) {
                    scheduler.onTaskCompleted(mTask.getTaskId());
                }
            }
        }
        
        /**
         * 下载单个文件
         * @param file 文件信息
         */
        private void downloadFile(DownloadFileInfo file, java.util.concurrent.CountDownLatch latch) {
            mFileDownloader.downloadFile(file, new FileDownloader.DownloadCallback() {
                @Override
                public void onProgress(int progress, long downloadedBytes, long totalBytes) {
                    Log.d(TAG, "downloadFile: Progress for file " + file.getFileName() + 
                        ": " + progress + "% (" + downloadedBytes + "/" + totalBytes + ")");
                    // 更新文件进度到数据库
                    updateFileProgress(file, downloadedBytes);
                }

                @Override
                public void onSuccess(DownloadFileInfo fileInfo) {
                    Log.d(TAG, "downloadFile: Successfully downloaded file: " + fileInfo.getFileName());
                    // 更新文件状态为完成
                    updateFileStatus(fileInfo, DownloadConstants.STATUS_COMPLETED);
                    // 减少计数器
                    latch.countDown();
                }

                @Override
                public void onError(DownloadFileInfo fileInfo, Exception error) {
                    Log.e(TAG, "downloadFile: Error downloading file: " + fileInfo.getFileName(), error);
                    // 更新文件状态为失败
                    updateFileStatus(fileInfo, DownloadConstants.STATUS_FAILED);
                    // 减少计数器
                    latch.countDown();
                }
            }, this); // 传递PauseChecker
        }
        
        /**
         * 分片下载文件
         * @param file 文件信息
         * @param chunks 分片列表
         */
        private void downloadFileWithChunks(DownloadFileInfo file, List<DownloadChunk> chunks, java.util.concurrent.CountDownLatch latch) {
            mChunkedFileDownloader.downloadFileWithChunks(file, chunks, new ChunkedFileDownloader.ChunkDownloadCallback() {
                @Override
                public void onProgress(int progress, long downloadedBytes, long totalBytes) {
                    Log.d(TAG, "downloadFileWithChunks: Progress for file " + file.getFileName() + 
                        ": " + progress + "% (" + downloadedBytes + "/" + totalBytes + ")");
                    // 更新文件进度到数据库
                    updateFileProgress(file, downloadedBytes);
                }

                @Override
                public void onSuccess(DownloadFileInfo fileInfo) {
                    Log.d(TAG, "downloadFileWithChunks: Successfully downloaded file: " + fileInfo.getFileName());
                    // 更新文件状态为完成
                    updateFileStatus(fileInfo, DownloadConstants.STATUS_COMPLETED);
                    // 减少计数器
                    latch.countDown();
                }

                @Override
                public void onError(DownloadFileInfo fileInfo, Exception error) {
                    Log.e(TAG, "downloadFileWithChunks: Error downloading file: " + fileInfo.getFileName(), error);
                    // 更新文件状态为失败
                    updateFileStatus(fileInfo, DownloadConstants.STATUS_FAILED);
                    // 减少计数器
                    latch.countDown();
                }
            }, this); // 传递PauseChecker
        }
        
        /**
         * 下载单个文件（不等待完成）
         * @param file 文件信息
         */
        private void downloadFile(DownloadFileInfo file) {
            downloadFile(file, new java.util.concurrent.CountDownLatch(0)); // 不需要等待
        }
        
        /**
         * 分片下载文件（不等待完成）
         * @param file 文件信息
         * @param chunks 分片列表
         */
        private void downloadFileWithChunks(DownloadFileInfo file, List<DownloadChunk> chunks) {
            downloadFileWithChunks(file, chunks, new java.util.concurrent.CountDownLatch(0)); // 不需要等待
        }
        
        /**
         * 更新文件进度到数据库
         * @param file 文件信息
         * @param downloadedBytes 已下载字节数
         */
        private void updateFileProgress(DownloadFileInfo file, long downloadedBytes) {
            try {
                DownloadManager downloadManager = DownloadManager.getInstance();
                // 计算增量
                long delta = downloadedBytes - file.getDownloadedSize();
                // 更新文件已下载字节数
                file.setDownloadedSize(downloadedBytes);
                file.setUpdateTime(System.currentTimeMillis());
                // 更新到数据库
                downloadManager.updateFileProgress(file.getFileId(), downloadedBytes);
                // 同时更新任务的总下载量
                if (delta > 0) {
                    updateTaskProgress(file.getTaskId(), delta);
                }
            } catch (Exception e) {
                Log.e(TAG, "updateFileProgress: Error updating file progress", e);
            }
        }
        
        /**
         * 更新任务进度到数据库
         * @param taskId 任务ID
         * @param fileDownloadedBytes 文件已下载字节数
         */
        private void updateTaskProgress(long taskId, long fileDownloadedBytes) {
            try {
                DownloadManager downloadManager = DownloadManager.getInstance();
                // 更新到数据库
                downloadManager.updateTaskProgress(taskId, fileDownloadedBytes);
            } catch (Exception e) {
                Log.e(TAG, "updateTaskProgress: Error updating task progress", e);
            }
        }
        
        /**
         * 更新文件状态到数据库
         * @param file 文件信息
         * @param status 状态
         */
        private void updateFileStatus(DownloadFileInfo file, int status) {
            try {
                DownloadManager downloadManager = DownloadManager.getInstance();
                // 更新文件状态
                file.setStatus(status);
                file.setUpdateTime(System.currentTimeMillis());
                // 更新到数据库
                downloadManager.updateFileStatus(file.getFileId(), status);
            } catch (Exception e) {
                Log.e(TAG, "updateFileStatus: Error updating file status", e);
            }
        }
        
        /**
         * 更新多个文件的状态
         * @param files 文件列表
         * @param status 状态
         */
        private void updateFilesStatus(List<DownloadFileInfo> files, int status) {
            if (files != null) {
                for (DownloadFileInfo file : files) {
                    updateFileStatus(file, status);
                }
            }
        }
        
        @Override
        public boolean isPaused() {
            return mPaused;
        }
        
        public void pause() {
            Log.d(TAG, "DownloadRunnable: Pausing task, task ID: " + mTask.getTaskId());
            synchronized (mPauseLock) {
                mPaused = true;
            }
        }
        
        public void resume() {
            Log.d(TAG, "DownloadRunnable: Resuming task, task ID: " + mTask.getTaskId());
            synchronized (mPauseLock) {
                mPaused = false;
                mPauseLock.notifyAll();
            }
        }
        
        public void cancel() {
            Log.d(TAG, "DownloadRunnable: Cancelling task, task ID: " + mTask.getTaskId());
            synchronized (mPauseLock) {
                mCancelled = true;
                mPauseLock.notifyAll();
            }
        }
        
        /**
         * 更新任务状态到数据库
         * @param taskId 任务ID
         * @param status 状态
         */
        private void updateTaskStatus(long taskId, int status) {
            try {
                DownloadManager downloadManager = DownloadManager.getInstance();
                downloadManager.updateTaskStatus(taskId, status);
            } catch (Exception e) {
                Log.e(TAG, "updateTaskStatus: Error updating task status", e);
            }
        }
    }
}